#ifndef RBUF_H_INCLUDED
#define RBUF_H_INCLUDED
#include <stdint.h>

#ifndef RBUF_DT
#define RBUF_DT uint8_t
#endif

typedef struct rbuf{
	uint8_t	front;
	uint8_t back;
	uint8_t ctr;
	uint8_t sz;
	RBUF_DT data[1];
}Rbuf;

/* 定义rbuf使用的内存空间 */
#define DEF_RBUF_MEM( name, sz ) \
	uint8_t name[ ((sz) - 1 ) * sizeof(RBUF_DT) + sizeof( Rbuf ) ]


#define DEF_RBUF( name, sz ) \
	DEF_RBUF_MEM( name##_MEM, sz ); \
	Rbuf *name = (struct rbuf *)&name##_MEM;	\
	static const uint8_t name##_MEM_SZ = sz;


#define RBUF_SZ(rb) ( rb##_MEM_SZ )

static inline void rbuf_clear( Rbuf *rb )
{
	rb->ctr = 0;
	rb->front = 0;
	rb->back = 0;
}

#define rbuf_init( rb ) { \
	rb->sz = RBUF_SZ(rb); \
	rbuf_clear( rb ); \
}

/* careate ring buffer from mem space alloc by DEF_RBUF_MEM, sz is the sz use in DEF_RBUF_MEM */
static inline Rbuf * rbuf_create( uint8_t *mem, uint8_t sz )
{
	Rbuf *rb = ( Rbuf * )mem;
	rb->sz = sz;
	rbuf_clear( rb );
	return rb;
}
/* careate ring buffer from raw mem space, sz is the size of memspace */
static inline Rbuf * rbuf_createm( void *mem, size_t sz )
{
	Rbuf *rb = ( Rbuf * )mem;
	size_t numsz = (sz - sizeof( Rbuf ) + sizeof( RBUF_DT ) ) / sizeof( RBUF_DT );
	if( numsz > 255 ){
		numsz = 255;
	}
	rb->sz = numsz;
	rbuf_clear( rb );
	return rb;
}

static inline uint8_t rbuf_inc( Rbuf *rb, uint8_t val )
{
	++val;
	return	( val < rb->sz ) ? val : 0;
}
static inline uint8_t rbuf_dec( Rbuf *rb, uint8_t val )
{
	return ( val > 0 ) ? val-1 : rb->sz-1;
}

/* 向一个满了的队中加入元素，会覆盖队首的数据，但是我们保证数据的顺序不会变化 */
static inline void rbuf_push( Rbuf *rb, RBUF_DT d )
{
	rb->data[rb->back] = d;
	rb->back = rbuf_inc( rb, rb->back );
	if( rb->ctr < rb->sz ){
		++rb->ctr;
	}else{
		rb->front = rbuf_inc( rb, rb->front );
	}
}

/* 如果队空，则不会有任何动作 */
static inline void rbuf_pop( Rbuf *rb )
{
	if( rb->ctr > 0 ){
		rb->front = rbuf_inc( rb, rb->front );
		--rb->ctr;
	}
}

/* 返回队首元素 */
static inline RBUF_DT rbuf_front( const Rbuf *rb )
{
	return rb->data[rb->front];
}

/* 返回队首元素，并修改队中指针 */
static inline RBUF_DT rbuf_pop_front( Rbuf *rb )
{
	RBUF_DT data = rbuf_front( rb );
	rbuf_pop( rb );
	return data;
}

static inline uint8_t rbuf_size( const Rbuf *rb )
{
	return rb->ctr;
}
static inline bool rbuf_empty( const Rbuf *rb )
{
	return PARSE_BOOL( rb->ctr == 0 );
}
static inline bool rbuf_full( const Rbuf *rb )
{
	return PARSE_BOOL( rb->ctr >= rb->sz );
}

#endif /* RBUF_H_INCLUDED */

